/*******************************************************************************
* Copyright 2013 SAP AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.sap.core.odata.core.rest;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.core.Response;
import com.sap.core.odata.api.ODataService;
import com.sap.core.odata.api.ODataServiceFactory;
import com.sap.core.odata.api.commons.ODataHttpMethod;
import com.sap.core.odata.api.exception.MessageReference;
import com.sap.core.odata.api.exception.ODataException;
import com.sap.core.odata.api.exception.ODataNotImplementedException;
import com.sap.core.odata.api.processor.ODataRequest;
import com.sap.core.odata.api.processor.ODataResponse;
import com.sap.core.odata.core.ODataContextImpl;
import com.sap.core.odata.core.ODataExceptionWrapper;
import com.sap.core.odata.core.ODataRequestHandler;
/**
* @author SAP AG
*/
public final class ODataSubLocator {
private ODataServiceFactory serviceFactory;
private ODataRequest request;
@GET
public Response handleGet() throws ODataException {
return handle(ODataHttpMethod.GET);
}
@PUT
public Response handlePut() throws ODataException {
return handle(ODataHttpMethod.PUT);
}
@PATCH
public Response handlePatch() throws ODataException {
return handle(ODataHttpMethod.PATCH);
}
@MERGE
public Response handleMerge() throws ODataException {
return handle(ODataHttpMethod.MERGE);
}
@DELETE
public Response handleDelete() throws ODataException {
return handle(ODataHttpMethod.DELETE);
}
@POST
public Response handlePost(@HeaderParam("X-HTTP-Method") final String xHttpMethod) throws ODataException {
Response response;
if (xHttpMethod == null) {
response = handle(ODataHttpMethod.POST);
} else {
/* tunneling */
if ("MERGE".equals(xHttpMethod)) {
response = handle(ODataHttpMethod.MERGE);
} else if ("PATCH".equals(xHttpMethod)) {
response = handle(ODataHttpMethod.PATCH);
} else if (HttpMethod.DELETE.equals(xHttpMethod)) {
response = handle(ODataHttpMethod.DELETE);
} else if (HttpMethod.PUT.equals(xHttpMethod)) {
response = handle(ODataHttpMethod.PUT);
} else if (HttpMethod.GET.equals(xHttpMethod)) {
response = handle(ODataHttpMethod.GET);
} else if (HttpMethod.POST.equals(xHttpMethod)) {
response = handle(ODataHttpMethod.POST);
} else if (HttpMethod.HEAD.equals(xHttpMethod)) {
response = handleHead();
} else if (HttpMethod.OPTIONS.equals(xHttpMethod)) {
response = handleOptions();
} else {
response = returnNotImplementedResponse(ODataNotImplementedException.TUNNELING);
}
}
return response;
}
private Response returnNotImplementedResponse(final MessageReference messageReference) {
// RFC 2616, 5.1.1: "An origin server SHOULD return the status code [...]
// 501 (Not Implemented) if the method is unrecognized [...] by the origin server."
ODataContextImpl context = new ODataContextImpl(request, serviceFactory);
context.setRequest(request);
context.setAcceptableLanguages(request.getAcceptableLanguages());
context.setPathInfo(request.getPathInfo());
context.setServiceFactory(serviceFactory);
ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(context, request.getQueryParameters(), request.getAcceptHeaders());
ODataResponse response = exceptionWrapper.wrapInExceptionResponse(new ODataNotImplementedException(messageReference));
return RestUtil.convertResponse(response);
}
@OPTIONS
public Response handleOptions() throws ODataException {
// RFC 2616, 5.1.1: "An origin server SHOULD return the status code [...]
// 501 (Not Implemented) if the method is unrecognized or not implemented
// by the origin server."
return returnNotImplementedResponse(ODataNotImplementedException.COMMON);
}
@HEAD
public Response handleHead() throws ODataException {
// RFC 2616, 5.1.1: "An origin server SHOULD return the status code [...]
// 501 (Not Implemented) if the method is unrecognized or not implemented
// by the origin server."
return returnNotImplementedResponse(ODataNotImplementedException.COMMON);
}
private Response handle(final ODataHttpMethod method) throws ODataException {
request = ODataRequest.fromRequest(request).method(method).build();
ODataContextImpl context = new ODataContextImpl(request, serviceFactory);
ODataService service = serviceFactory.createService(context);
context.setService(service);
service.getProcessor().setContext(context);
ODataRequestHandler requestHandler = new ODataRequestHandler(serviceFactory, service, context);
final ODataResponse odataResponse = requestHandler.handle(request);
final Response response = RestUtil.convertResponse(odataResponse);
return response;
}
public static ODataSubLocator create(final SubLocatorParameter param) throws ODataException {
ODataSubLocator subLocator = new ODataSubLocator();
subLocator.serviceFactory = param.getServiceFactory();
subLocator.request = ODataRequest.acceptableLanguages(param.getHttpHeaders().getAcceptableLanguages())
.acceptHeaders(RestUtil.extractAcceptHeaders(param))
.body(RestUtil.contentAsStream(RestUtil.extractRequestContent(param)))
.pathInfo(RestUtil.buildODataPathInfo(param))
.queryParameters(RestUtil.convertToSinglevaluedMap(param.getUriInfo().getQueryParameters()))
.requestHeaders(param.getHttpHeaders().getRequestHeaders())
.contentType(RestUtil.extractRequestContentType(param).toContentTypeString())
.build();
return subLocator;
}
private ODataSubLocator() {
super();
}
}